﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml.Linq;

namespace IBoLT.SettingWindows
{
	/// <summary>
	/// Логика взаимодействия для Mandelbrot.xaml
	/// </summary>
	public partial class Mandelbrot : Window
	{
		// Для перемещения препросмотра мышью
		private bool mouseDown = false;
		private Point mousePositionClick;

		// Экземпляр класса для построения фрактала (доступ к полям public)
		public Fractals.AlgebraicFractals fractal = new Fractals.AlgebraicFractals();
		public TextureSettings STexture;

		private CommandBinding commBind;

		public Mandelbrot(System.Drawing.Bitmap sourcePreview, TextureSettings STexture)
		{
			this.STexture = STexture;

			InitializeComponent();

			// Добавляю обработчики к событиям в коде, т.к. для их работы необходимо созданая форма
			sliderLvlOriginal.ValueChanged += hMandelbrotSliderPreview;
			sliderLvlCreate.ValueChanged += hMandelbrotSliderPreview;

			wPreview.MouseWheel += wPreview_MouseWheel;
			wPreview.MouseLeftButtonDown += wPreview_MouseLeftButtonDown;
			wPreview.MouseMove += wPreview_MouseMove;
			wPreview.MouseLeftButtonUp += wPreview_MouseLeftButtonUp;
			wPreview.MouseLeave += wPreview_MouseLeave;

			typeFractal.SelectionChanged += typeFractal_SelectionChanged;

			// Привязка команд к обработчикам //
			commBind = new CommandBinding(CommandsIBoLT.cMandelbrotPreview, hMandelbrotPreviewEx);		this.CommandBindings.Add(commBind);
			commBind = new CommandBinding(CommandsIBoLT.cMandelbrotGenerate, hMandelbrotGenerateEx);	this.CommandBindings.Add(commBind);
			commBind = new CommandBinding(CommandsIBoLT.cMandelbrotChColor, hMandelbrotChColorEx);

			fractal.Texture = sourcePreview;
			wPreview.Width = sourcePreview.Width;
			wPreview.Height = sourcePreview.Height;

			Double step = 0.015;
			wXmin.Text = (-sourcePreview.Width / 2 * step).ToString();
			wXmax.Text = (sourcePreview.Width / 2 * step).ToString();
			wYmin.Text = (-sourcePreview.Height / 2 * step).ToString();
			wYmax.Text = (sourcePreview.Height / 2 * step).ToString();

			// Вывожу палитру на форму
			ApplyPaletteToForm();
			typeFractal_SelectionChanged(null, null);
		}

		// Zoom
		private void wPreview_MouseWheel(object sender, MouseWheelEventArgs e)
		{
			double zoom = e.Delta > 0 ? 0.5 : 2;
			
			double hCenter = (fractal.xMax + fractal.xMin) / 2;
			double vCenter = (fractal.yMax + fractal.yMin) / 2;

			wXmin.Text = (((fractal.xMin - hCenter) * zoom) + hCenter).ToString();
			wXmax.Text = (((fractal.xMax - hCenter) * zoom) + hCenter).ToString();
			wYmin.Text = (((fractal.yMin - vCenter) * zoom) + vCenter).ToString();
			wYmax.Text = (((fractal.yMax - vCenter) * zoom) + vCenter).ToString();

			CommandsIBoLT.cMandelbrotPreview.Execute(null, this);
		}
		private void wPreview_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			mouseDown = true;
			mousePositionClick = e.GetPosition(wPreview);
		}
		private void wPreview_MouseMove(object sender, MouseEventArgs e)
		{
			if (mouseDown)
			{
				Point tmpMousePosition =  e.GetPosition(wPreview);

				double moveX = (mousePositionClick.X - tmpMousePosition.X) * (fractal.xMax - fractal.xMin) / 1000;
				double moveY = (mousePositionClick.Y - tmpMousePosition.Y) * (fractal.yMax - fractal.yMin) / 1000;
				//MessageBox.Show("x: " + moveX.ToString() + " y: " + moveY.ToString());
				wXmin.Text = (fractal.xMin + moveX).ToString();
				wXmax.Text = (fractal.xMax + moveX).ToString();
				wYmin.Text = (fractal.yMin + moveY).ToString();
				wYmax.Text = (fractal.yMax + moveY).ToString();

				CommandsIBoLT.cMandelbrotPreview.Execute(null, this);
			}
		}
		private void wPreview_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
			mouseDown = false;
		}
		private void wPreview_MouseLeave(object sender, MouseEventArgs e)
		{
			mouseDown = false;
		}

		// Обработчик изменения значения ползунков
		private void hMandelbrotSliderPreview(object sender, RoutedPropertyChangedEventArgs<double> e)
		{
			CommandsIBoLT.cMandelbrotPreview.Execute(null, this);
		}

		// Отображаю на форме настройку палитры для раскраски фрактала
		private void ApplyPaletteToForm()
		{
			// Размер кнопок для вывода цветов
			int buttonSize = 16;
			// Размеры поля для вывода палитры
			int paletteSize = (int)(Math.Sqrt(fractal.palette.Length) + 0.5) * buttonSize;

			wPalette.Width = paletteSize;
			wPalette.Height = paletteSize;

			for (int i = 0; i < fractal.palette.Length; ++i)
			{
				Button b = new Button();
				b.Width = buttonSize;
				b.Height = buttonSize;
				System.Drawing.Color clr = System.Drawing.Color.FromArgb(fractal.palette[i]);
				b.Background = new SolidColorBrush(Color.FromRgb(clr.R, clr.G, clr.B));
				b.TabIndex = i;
				wPalette.Children.Add(b);

				b.CommandBindings.Add(commBind);
				b.Command = CommandsIBoLT.cMandelbrotChColor;
			}
		}

		private bool GetDataFromForm()
		{
			bool flag = false;

			if (fractal.xMin != Convert.ToDouble(wXmin.Text.Replace(".", ",")))
			{
				fractal.xMin = Convert.ToDouble(wXmin.Text.Replace(".", ","));
				flag = true;
			}
			if (fractal.xMax != Convert.ToDouble(wXmax.Text.Replace(".", ",")))
			{
				fractal.xMax = Convert.ToDouble(wXmax.Text.Replace(".", ","));
				flag = true;
			}
			if (fractal.yMin != Convert.ToDouble(wYmin.Text.Replace(".", ",")))
			{
				fractal.yMin = Convert.ToDouble(wYmin.Text.Replace(".", ","));
				flag = true;
			}
			if (fractal.yMax != Convert.ToDouble(wYmax.Text.Replace(".", ",")))
			{
				fractal.yMax = Convert.ToDouble(wYmax.Text.Replace(".", ","));
				flag = true;
			}
			if (fractal.iterations != Convert.ToInt32(wIterations.Text))
			{
				fractal.iterations = Convert.ToInt32(wIterations.Text);
				flag = true;
			}

			if (fractal.c.Re != Convert.ToDouble(wCRe.Text.Replace(".", ",")))
			{
				fractal.c.Re = Convert.ToDouble(wCRe.Text.Replace(".", ","));
				flag = true;
			}
			if (fractal.c.Im != Convert.ToDouble(wCIm.Text.Replace(".", ",")))
			{
				fractal.c.Im = Convert.ToDouble(wCIm.Text.Replace(".", ","));
				flag = true;
			}

			return flag;
		}

		private bool Getlvl()
		{
			bool flag = false;

			if (fractal.lvlOriginal != sliderLvlOriginal.Value)
			{
				fractal.lvlOriginal = sliderLvlOriginal.Value;
				flag = true;
			}
			if (fractal.lvlCreate != sliderLvlCreate.Value)
			{
				fractal.lvlCreate = sliderLvlCreate.Value;
				flag = true;
			}

			return flag;
		}

		// Обработчик выбора фрактала
		private void typeFractal_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			switch (typeFractal.SelectedIndex)
			{
				case 0:
					fractal.delFractal = Fractals.AlgebraicFractals.Julia;
					wCRe.Text = "0.01";
					wCIm.Text = "0.7";
					break;
				case 1:
					fractal.delFractal = Fractals.AlgebraicFractals.Mandelbrot;
					wCRe.Text = "0";
					wCIm.Text = "0";
					break;
			}

			CommandsIBoLT.cMandelbrotPreview.Execute(null, this);
		}

		// Обработчик кнопок выбора цвета
		private void hMandelbrotChColorEx(object sender, ExecutedRoutedEventArgs e)
		{
			System.Windows.Forms.ColorDialog colorDialog = new System.Windows.Forms.ColorDialog();
			Button btn = (Button)sender;
			
			if (colorDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				System.Drawing.Color SDColor = colorDialog.Color;
				Color SWMColor = new Color();
				
				SWMColor.A = SDColor.A;
				SWMColor.R = SDColor.R;
				SWMColor.G = SDColor.G;
				SWMColor.B = SDColor.B;
				
				Brush brush = new SolidColorBrush(SWMColor);
				btn.Background = brush;

				fractal.palette[btn.TabIndex] = colorDialog.Color.ToArgb();
			}

			wPreview.Source = SystemDrawingHelper.BitmapToBitmapImage(fractal.ToBitmap());
		}

		// Обработчик кнопки "Просмотр"
		private void hMandelbrotPreviewEx(object sender, ExecutedRoutedEventArgs e)
		{
			GetDataFromForm();
			Getlvl();
			fractal.Calculate();
			wPreview.Source = SystemDrawingHelper.BitmapToBitmapImage(fractal.ToBitmap());
		}

		// Обработчик кнопки "Генерировать"
		private void hMandelbrotGenerateEx(object sender, ExecutedRoutedEventArgs e)
		{
			GetDataFromForm();

			XElement juliaC;
			switch (fractal.delFractal.Method.Name)
			{
				case "Julia":
					juliaC = new XElement("Точка_С",
						new XAttribute("Реальная_часть", fractal.c.Re),
						new XAttribute("Мнимая_часть", fractal.c.Im));
					break;
				default:
					juliaC = new XElement("Точка_Z",
						new XAttribute("Реальная_часть", fractal.c.Re),
						new XAttribute("Мнимая_часть", fractal.c.Im));
					break;
			}

			XElement color = new XElement("Цвета_итераций");
			for (int i = 0; i < fractal.palette.Length; ++i)
			{
				color.SetAttributeValue("id_" + i.ToString(), fractal.palette[i]);
			}

			STexture.Settings.Root.Add(new XElement("Генератор",
				new XAttribute("Название", fractal.delFractal.Method.Name),
				new XElement("Параметры",
					new XElement("Позиция",
						new XAttribute("X_минимальная", fractal.xMin),
						new XAttribute("X_максимальная", fractal.xMax),
						new XAttribute("Y_минимальная", fractal.yMin),
						new XAttribute("Y_максимальная", fractal.yMax)),
					new XElement(juliaC),
					new XElement("Итераций",
						new XAttribute("Количество_итераций", fractal.iterations)),
					new XElement(color),
					new XElement("Наложения",
						new XAttribute("Исходная_текстура", fractal.lvlOriginal),
						new XAttribute("Генериремая_текстура", fractal.lvlCreate)))));

				// Диалог успешен
				DialogResult = true;
		}
	}
}
